package com.ruoyi.aitcommon.api;

import java.lang.reflect.UndeclaredThrowableException;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONObject;
import com.ruoyi.aitcommon.anotation.ApiLog;
import com.ruoyi.aitcommon.config.ConfigManager;
import com.ruoyi.aitcommon.service.FlowService;
import com.ruoyi.aitcommon.utils.AITConst;
import com.ruoyi.aitcommon.utils.ExceptionUtils;
import com.ruoyi.aitcommon.utils.JSONResult;
import com.ruoyi.aitcommon.utils.LogUtils;
import com.ruoyi.aitcommon.vo.FlowContextVO;

import cn.hutool.core.util.StrUtil;

@RestController
@RequestMapping("/ait/common/flow")
public class FlowOperation {
	@Autowired
	FlowService flowService;
	@Autowired
	ConfigManager configManager;
	//${ait.configdir:}配置最后的冒号代表默认值空字符串
	@Value("${ait.probe.mappath:}")
	private String probePath;
	//${ait.probe.delay:0}配置最后的冒号代表默认值0
	@Value("${ait.probe.delay:0}")
	private int probeDelay;
	
	/**
	 * Flow同步执行
	 * @param flow flow编码
	 * @param args 传入参数
	 * @return Map对象 Flow简报
	 */
	@ApiLog("Flow手工触发")
	@GetMapping("/template")
	public JSONObject template(String flow, String[] args) {
		try {
			if (StringUtils.isBlank(flow))
				throw new Exception("参数flow为空!");
			
//			调用核心FlowService
			@SuppressWarnings("unused")
			Object retobj = flowService.templateServiceEx(flow, args);
			
//			处理返回
			if(retobj instanceof JSONObject) {
				JSONObject retjson=(JSONObject)retobj;
				return retjson;
			}else if(retobj instanceof List) {
//				返回的指定数据为集合
				List<Object> retlist=(List<Object>)retobj;
				for(Object retobj1:retlist) {
					if(retobj1 instanceof JSONObject) {
						JSONObject retjson1=(JSONObject)retobj1;
						if(retjson1.containsKey("code") && !retjson1.getString("code").equals(AITConst.SUCCESSCODE)) {
							return JSONResult.error(retjson1.getString("msg"),retobj);
						}
					}
				}
			}
			return JSONResult.success(retobj);
		} catch (Exception ex) {
//			切面报错时,类型为UndeclaredThrowableException
//			flow执行的报错都在简报中,只有flow切面的报错会在这里
			if(ex instanceof UndeclaredThrowableException&&ex.getCause()!=null) {
				return JSONResult.error(ex.getCause().getMessage());
			}else {
				return JSONResult.error(ex.getMessage());	
			}
		}
	}

	/**
	 * Flow异步执行
	 * @param flow flow编码
	 * @param sec 延迟秒数
	 * @param args flow参数
	 * @return
	 */
	@GetMapping("/templateAsync")
	public JSONObject templateAsync(String flow,int sec, String[] args){
		
		String msg="延时执行["+sec+"]秒,执行模板:["+flow+"],参数:["+StrUtil.join(",",Arrays.asList(args))+"]";
		//启动新线程执行
		Thread async=new Thread(()->{
			//先延时XX秒
			LogUtils.info(msg);
			if(sec>0) {
				try {
					Thread.sleep(sec*1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			//在执行模板
			this.template(flow, args);
		});
		//启动线程
		async.start();
		
		return JSONResult.success("启动新线程执行,"+msg);
	}
	
	/**
	 * 模板探针
	 * @param type 探针类型
	 * @param args 调用参数
	 * @param async 是否异步执行
	 * @return Map对象 Flow简报
	 * @throws Exception
	 */
	@GetMapping("/templateProbe")
	public JSONObject templateProbe(String type,String[] args,boolean async){
		try {
			if(StrUtil.isBlank(probePath))
				throw new Exception("[ait.probe.mappath]配置为空");
			
//			获取探针配置
			Object probeObj = configManager.getContextByParm(probePath);
			ExceptionUtils.checkBlankOrUndefined(probeObj, "获取参数[{}]为空",probePath);
			
			Map<String,Object> probeMap=(Map<String,Object>)probeObj;
			
			if(!probeMap.containsKey(type)) {
				String msg=String.format("映射配置表中,[%s]不存在对应流程", type);
				throw new Exception(msg);
			}
			
//			获取flow/path属性
			Map<String,Object> probeItem=(Map<String,Object>)probeMap.get(type);
			String flow=(String)probeItem.get("flow");
			
//			调用flow
			if(async) {
				return this.templateAsync(flow, probeDelay, args);	
			}else {
				return this.template(flow, args);
			}
		}catch(Exception ex) {
			return JSONResult.error(ex.getMessage(),ex);
		}
		
	}
}
